#include <iostream>

#include "trie.hpp"

bool insert(trie& trie, const std::string& str) {
    if(!contains(trie,str)){
        if(str.length()==0){
        trie.size++;
        trie.root->children[trie.size]=new trie_node;
        trie.root->children[trie.size]->payload='1'; 
        trie.root->children[trie.size]->children[0]= new trie_node;
        trie.root->children[trie.size]->children[0]->payload='0';
        trie.root->children[trie.size]->children[0]->is_terminal=true;

        }else{

        trie.size++;
        trie.root->children[trie.size]=new trie_node;
        trie.root->children[trie.size]->payload='1';
        for(int i=0;i<str.length();i++){
            trie.root->children[trie.size]->children[i]= new trie_node;
            trie.root->children[trie.size]->children[i]->payload=str.at(i);
              trie.root->children[trie.size]->children[i]->parent=  trie.root->children[0];
       
        if(i==str.length()-1){
              trie.root->children[trie.size]->children[i]->is_terminal=true;
           }
        }}
        return true;
    }
    
    
    return false;
}

bool contains(const trie& trie, const std::string& str) {
    bool found=false;
   
    if(trie.size>0 ){
        if(str.size()==0){
            for(int i=1;i<=trie.size;i++){
                if(trie.root->children[i]->children[0]->payload=='0'){
                    found= true;
                    break;
                }
            
            }
        }
        else{
            for (int x=1; x<=trie.size;x++){
                 int counter=0,y=0;
                                     

                while(trie.root->children[x]->children[y]->is_terminal!=true){
                    counter++;
                    y++;
                }
                 counter++;
                 if(counter==str.size()){
                    for(int u=0;u<counter;u++){
                        if(str.at(u)==trie.root->children[x]->children[u]->payload){
                            found=true;
                        }else{
                            found=false;
                            break;
                        }
                    
                    }
                    if(found==true){
                        return true;
                        
                    }
                 
                 
                 }
            
            
            }
        
        }
    }
    return found;
}

void insert_all(trie& trie, const std::vector<std::string>& items) {
    for (int i=0; i<items.size();i++) {
        insert(trie,items.at(i));
    }


}

void init(trie& trie) {
    delete trie.root;
    
   trie.root=new trie_node;
   
   trie.root->is_terminal=false;
   trie.root->payload='0';
   
   
   
    
}
void shiftbackone(trie& trie, int i){
    for(i=i;i<trie.size;i++){
        trie.root->children[i]=trie.root->children[i+1];
    
    }
   

}
bool erase(trie& trie, const std::string& str) {
     bool found=false;
   
    if(trie.size>0 ){
        if(str.size()==0){
            for(int i=1;i<=trie.size;i++){
                if(trie.root->children[i]->children[0]->payload=='0'){
                    found= true;
                    delete trie.root->children[i]->children[0];
                    trie.root->children[i]->children[0]=nullptr;
                    delete trie.root->children[i];
                    trie.root->children[i]=nullptr;
                    shiftbackone(trie,i);
                    trie.size--;
                    break;
                }
            
            }
        }
        else{
            for (int x=1; x<=trie.size;x++){
                 int counter=0,y=0;
                                     

                while(trie.root->children[x]->children[y]->is_terminal!=true){
                    counter++;
                    y++;
                }
                 counter++;
                 if(counter==str.size()){
                    for(int u=0;u<counter;u++){
                        if(str.at(u)==trie.root->children[x]->children[u]->payload){
                            found=true;
                        }else{
                            found=false;
                            break;
                        }
                    
                    }
                    if(found==true){
                        for(int m=0;m<str.size();m++){
                            delete trie.root->children[x]->children[m];
                            delete trie.root->children[x]->parent;
                            trie.root->children[x]->children[m]=nullptr;
                            trie.root->children[x]->parent=nullptr;
                            
                        
                        }
                        delete trie.root->children[x];
                        trie.root->children[x]=nullptr;
                        shiftbackone(trie,x);
                        trie.size--;
                        return true;
                        
                    }
                 
                 
                 }
            
            
            }
        
        }
    }
    return found;
}

void deallocate(trie& trie) {
    for(int i=0;i<=trie.size;i++){
         int x=0;
         if(trie.root->children[i]!=nullptr){
                  while(trie.root->children[i]->children[x]->is_terminal!=true){
                      delete trie.root->children[i]->children[x]->parent;
                      trie.root->children[i]->children[x]->parent=nullptr;
                      delete trie.root->children[i]->children[x];
                      trie.root->children[i]->children[x]=nullptr;
                      
                      
                      x++;  
                  }
                  delete trie.root->children[i]->children[x]->parent;
                  trie.root->children[i]->children[x]->parent=nullptr;
                  delete trie.root->children[i]->children[x];
                  trie.root->children[i]->children[x]=nullptr;
                    }
                  delete trie.root->children[i];
                  trie.root->children[i]=nullptr;
    
    }
   delete trie.root;
   trie.root=nullptr;
}

size_t size(const trie& trie) {
    return trie.size;
}

bool empty(const trie& trie) {
    return trie.size==0;
}
